//泛型在Typescript是非常重要的东西
//1.函数泛型
// function num(a: number, b: number): Array<number> {
//   return [a, b]
// }
// console.log(num(1, 2));
// function str(a: string, b: string): Array<string> {
//   return [a, b]
// }
// str('东方', '不败')

//使用泛型进行优化
// 语法为函数名字后面跟一个<参数名> 参数名可以随便写 例如我这儿写了T
// 当我们使用这个函数的时候把参数的类型传进去就可以了 （也就是动态类型）
function Add<T>(a: T, b: T): Array<T> {
  return [a, b]
}
console.log(Add(1, 2));
console.log(Add('1', '2'));
// 我们也可以使用不同的泛型参数名，只要在数量上和使用方法上能对应就行
function Sub<S, U>(a: S, b: U): Array<S | U> {
  const parms: Array<S | U> = [a, b]
  return parms
}
console.log(Sub<boolean, number>(true, 5));

//定义泛型接口
//声明接口的时候，在名字后面加上<参数> 使用的时候传递类型
interface MyInter<F> {
  (arg: F): F
}
function f<F>(arg: F): F {
  return arg
}
let result: MyInter<number> = f
console.log(result(123));

//对象字面量泛型
let foo: { <X>(arg: X): X }
foo = function <X>(arg: X) {
  return arg
}
console.log(foo(456));

//泛型约束
//我们期望在一个泛型的变量上面，获取其length属性 但是有的数据类型是没有length属性的
interface Len {
  length: number
}
function getLength<L extends Len>(arg: L) {
  // return arg.length //不存在属性length
  return arg.length
}
console.log(getLength<string>('123'));

//使用keyof约束对象
function props<O, K extends keyof O>(obj: O, key: K) {
  return obj[key]
}
let objs = { a: 2, b: 4, c: 6, d: 8 }
console.log(props(objs, 'd'));

//泛型类
class Subs<B>{
  attr: B[] = []
  add(a: B): B[] {
    return [a]
  }
}
let sub = new Subs<number>()
sub.attr = [89]
console.log(sub.attr = [89]);
console.log(sub.add(6));


